package com.swift.violent.mainstay.security.interceptor;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.swift.violent.mainstay.security.exception.PreAuthorizeException;
import com.swift.violent.mainstay.security.model.LoginUser;
import com.swift.violent.mainstay.security.model.PreAuthorizeBean;
import com.swift.violent.mainstay.security.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;

/**
 * 自定义权限实现
 *
 * @author ruoyi
 */
@Component
public class PreAuthorizeInterceptor {
    private static TokenService TOKEN_SERVICE;

    /**
     * Instantiates a new Pre authorize interceptor.
     *
     * @param tokenService the token service
     */
    @Autowired
    public PreAuthorizeInterceptor(TokenService tokenService) {
        PreAuthorizeInterceptor.TOKEN_SERVICE = tokenService;
    }

    /**
     * 所有权限标识
     */
    private static final String ALL_PERMISSION = "*:*:*";

    /**
     * 管理员角色权限标识
     */
    private static final String SUPER_ADMIN = "admin";

    /**
     * 数组为0时
     */
    private static final Integer ARRAY_EMPTY = 0;

    /**
     * 拦截器使用注解拦截器
     *
     * @param options the options
     *
     * @return true 继续，false 权限异常
     */
    public static boolean annotationInterceptor(String preAuthorizeOption) {
        final PreAuthorizeBean annotation = JSON.parseObject(preAuthorizeOption, PreAuthorizeBean.class);
        if (Objects.isNull(annotation)) {
            return true;
        }
        if (StrUtil.isNotEmpty(annotation.getHasPermi())) {
            if (PreAuthorizeInterceptor.hasPermi(annotation.getHasPermi())) {
                return true;
            }
            throw new PreAuthorizeException();
        } else if (StrUtil.isNotEmpty(annotation.getLacksPermi())) {
            if (PreAuthorizeInterceptor.lacksPermi(annotation.getLacksPermi())) {
                return true;
            }
            throw new PreAuthorizeException();
        } else if (Objects.nonNull(annotation.getHasAnyPermi()) && ARRAY_EMPTY < annotation.getHasAnyPermi().length) {
            if (PreAuthorizeInterceptor.hasAnyPermi(annotation.getHasAnyPermi())) {
                return true;
            }
            throw new PreAuthorizeException();
        } else if (StrUtil.isNotEmpty(annotation.getHasRole())) {
            if (PreAuthorizeInterceptor.hasRole(annotation.getHasRole())) {
                return true;
            }
            throw new PreAuthorizeException();
        } else if (StrUtil.isNotEmpty(annotation.getLacksRole())) {
            if (PreAuthorizeInterceptor.lacksRole(annotation.getLacksRole())) {
                return true;
            }
            throw new PreAuthorizeException();
        } else if (Objects.nonNull(annotation.getHasAnyRoles()) && ARRAY_EMPTY < annotation.getHasAnyRoles().length) {
            if (PreAuthorizeInterceptor.hasAnyRoles(annotation.getHasAnyRoles())) {
                return true;
            }
            throw new PreAuthorizeException();
        }
        return true;
    }

    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     *
     * @return 用户是否具备某权限 boolean
     */
    private static boolean hasPermi(String permission) {
        final LoginUser userInfo = TOKEN_SERVICE.getLoginUser();
        return Objects.nonNull(userInfo)
                && CollUtil.isNotEmpty(userInfo.getPermissions())
                && hasPermissions(userInfo.getPermissions(), permission);
    }

    /**
     * 验证用户是否不具备某权限，与 hasPermi逻辑相反
     *
     * @param permission 权限字符串
     *
     * @return 用户是否不具备某权限 boolean
     */
    private static boolean lacksPermi(String permission) {
        return !hasPermi(permission);
    }

    /**
     * 验证用户是否具有以下任意一个权限
     *
     * @param permissions 权限列表
     *
     * @return 用户是否具有以下任意一个权限 boolean
     */
    private static boolean hasAnyPermi(String[] permissions) {
        final LoginUser userInfo = TOKEN_SERVICE.getLoginUser();
        return Objects.nonNull(userInfo)
                && CollUtil.isNotEmpty(userInfo.getPermissions())
                && Arrays.stream(permissions).anyMatch(permission -> permission != null && hasPermissions(userInfo.getPermissions(), permission));
    }

    /**
     * 判断用户是否拥有某个角色
     *
     * @param role 角色字符串
     *
     * @return 用户是否具备某角色 boolean
     */
    private static boolean hasRole(String role) {
        final LoginUser userInfo = TOKEN_SERVICE.getLoginUser();
        return Objects.nonNull(userInfo)
                && CollUtil.isNotEmpty(userInfo.getRoles())
                && userInfo.getRoles().stream().anyMatch(roleKey -> SUPER_ADMIN.equals(roleKey) || roleKey.equals(role));
    }

    /**
     * 验证用户是否不具备某角色，与 isRole逻辑相反。
     *
     * @param role 角色名称
     *
     * @return 用户是否不具备某角色 boolean
     */
    private static boolean lacksRole(String role) {
        return !hasRole(role);
    }

    /**
     * 验证用户是否具有以下任意一个角色
     *
     * @param roles 角色列表
     *
     * @return 用户是否具有以下任意一个角色 boolean
     */
    private static boolean hasAnyRoles(String[] roles) {
        final LoginUser userInfo = TOKEN_SERVICE.getLoginUser();
        return Objects.nonNull(userInfo)
                && CollUtil.isNotEmpty(userInfo.getRoles())
                && Arrays.stream(roles).anyMatch(PreAuthorizeInterceptor::hasRole);
    }

    /**
     * 判断是否包含权限
     *
     * @param authorities 权限列表
     * @param permission  权限字符串
     *
     * @return 用户是否具备某权限
     */
    private static boolean hasPermissions(Collection<String> authorities, String permission) {
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(permission, x));
    }
}
